home *** CD-ROM | disk | FTP | other *** search
- /* dcalc v1.1 -- fits files onto disks */
- /* written 23 Dec 1993 by Mark Baker */
- /* modified 6 Jan 1994 by Mark Baker (Bugfix, added extra features) */
- /* modified 11 Jan 94 by Mark Baker (more bugs fixed) */
- /* This source code may be freely distributed and modified,
- but may not be used in a commercial product without the author's
- permission. A small charge for media and copying is allowed ( $6 max ). */
- /* For usage, type dcalc -help when compiled.
- This should be simple ANSI C. It calls the unix utilities
- ls, rm and mv. You will have to alter the source if your system
- uses different commands. Just alter the defines below.. */
-
- #define SYS_LIST "ls -l"
- #define SYS_DELETE "rm"
- #define SYS_RENAME "mv"
-
- /* includes */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
-
- /* defines */
- enum {FALSE, TRUE};
- #define ONE_K 1024L
- #define IBM_DD 720L * ONE_K
- #define IBM_HD 1440L * ONE_K
- #define DEF_SIZE IBM_DD
- #define Lnext(ptr) ptr = ptr->next
-
- /* structures and typedefs */
- struct ilist /* include list type */
- {
- char *pattern; /* pattern to include */
- struct ilist *next; /* next */
- };
-
- struct elist /* exclude list type */
- {
- char *pattern; /* pattern to exclude */
- struct elist *next; /* next */
- };
-
- struct plist /* path list type */
- {
- char *path; /* path */
- struct plist *next; /* next */
- };
-
- struct flist /* file list type */
- {
- char *name; /* file name */
- char *path; /* path */
- long size; /* size in bytes */
- struct flist *next; /* next */
- };
-
- struct opt /* options list type */
- {
- long disk_size; /* size of disks, in bytes */
- long reserved; /* size in bytes reserved for system */
- int output_to_file; /* flag - send output to file */
- int include_list; /* flag - use include list */
- int exclude_list; /* flag - use exclude list */
- int rename_files; /* flag - rename files */
- int backup; /* flag - use BACKUP mode */
- char *output_filename; /* file to output to */
- struct ilist *inc_list; /* include list */
- struct elist *exc_list; /* exclude list */
- struct plist *path_list; /* path list */
- };
-
- struct disklist /* disk list type */
- {
- struct flist *files; /* list of files on disk */
- long free_space; /* free space left */
- long used_space; /* space used on disk */
- float perc_used; /* space used as a % */
- int number; /* number of the disk */
- struct disklist *next; /* next */
- };
-
- /* function prototypes */
- int main(int argc, char *argv[]);
- void get_options(int argc, char *argv[]);
- struct flist *get_files(void);
- struct disklist *fit_files(struct flist *file_list_top);
- void show_results(struct disklist *disk_list_top);
-
- /* global variables */
- struct opt options; /* option list */
-
- /* calculator program to add up size of files to fit on IBM disks */
- int main(int argc, char *argv[])
- {
- struct flist *file_list;
- struct disklist *disk_list;
-
- /* get options from command line */
- get_options(argc, argv);
-
- /* load in filenames */
- file_list = get_files();
-
- /* fit files onto disk */
- disk_list = fit_files(file_list);
-
- /* output results */
- show_results(disk_list);
-
- return(0);
- }
-
- int str_match(char *src, char *match);
-
- void get_options(int argc, char *argv[])
- {
- int count, show_usage = FALSE;
- long num = 0;
- float ftmp;
- char *opt, *c;
- struct plist *cur_path;
- struct elist *cur_excl;
- struct ilist *cur_incl;
-
- /* clear options */
- options.disk_size = 0;
- options.output_to_file = FALSE;
- options.include_list = FALSE;
- options.exclude_list = TRUE;
- options.rename_files = FALSE;
- options.backup = FALSE;
- options.output_filename = NULL;
- options.inc_list = NULL;
- options.exc_list = (struct elist *)malloc(sizeof(struct elist));
- options.path_list = NULL;
- options.reserved = -1;
-
- cur_excl = options.exc_list;
- cur_excl->pattern = "dcalc.tmp";
- cur_excl->next = NULL;
-
- for (count = 1; count < argc; )
- if (argv[count][0] == '-')
- {
- /* an option */
- opt = argv[count] + 1;
- count++;
- /* flags */
- if (str_match(opt,"?"))
- {
- show_usage = TRUE;
- }
- else if (str_match(opt,"hd"))
- {
- options.disk_size = IBM_HD ;
- }
- else if (str_match(opt,"dd"))
- {
- options.disk_size = IBM_DD ;
- }
- else if (str_match(opt,"help"))
- {
- show_usage = TRUE;
- }
- else if (str_match(opt,"rename"))
- {
- options.rename_files = TRUE;
- }
- else if (str_match(opt,"backup"))
- {
- options.backup = TRUE;
- options.rename_files = FALSE;
- }
- if ((count < argc) && (argv[count][0] != '-'))
- {
- if (str_match(opt,"s"))
- {
- for (c = argv[count] ; *(c+1) != '\0' ; c++) ;
- if (toupper(*c) == 'K')
- {
- *c == '\0';
- if (sscanf(argv[count],"%d", &num))
- {
- options.disk_size = num * ONE_K;
- count++;
- }
- }
- else if (toupper(*c) == 'M')
- {
- *c == '\0';
- if (sscanf(argv[count],"%f", &ftmp))
- {
- options.disk_size = (long) (ftmp * (float)(ONE_K * ONE_K));
- count++;
- }
- }
- else if (sscanf(argv[count],"%d", &num))
- {
- options.disk_size = num;
- count++;
- }
- }
- else if (str_match(opt,"o"))
- {
- options.output_to_file = TRUE;
- options.output_filename = argv[count];
- count++;
- }
- else if (str_match(opt,"ls"))
- {
- /* add another path */
- if (options.path_list == NULL)
- {
- options.path_list = (struct plist *)malloc(sizeof(struct plist));
- cur_path = options.path_list;
- }
- else
- {
- cur_path->next = (struct plist *)malloc(sizeof(struct plist));
- Lnext(cur_path);
- }
- cur_path->path = argv[count];
- cur_path->next = NULL;
- count++;
- }
- else if (str_match(opt,"in"))
- {
- /* add to include list */
- while((count < argc) && (argv[count][0] != '-'))
- {
- if (options.inc_list == NULL)
- {
- options.inc_list = (struct ilist *)malloc(sizeof(struct ilist));
- options.include_list = TRUE;
- cur_incl = options.inc_list;
- }
- else
- {
- cur_incl->next = (struct ilist *)malloc(sizeof(struct ilist));
- Lnext(cur_incl);
- }
- cur_incl->pattern = argv[count];
- cur_incl->next = NULL;
- count++;
- }
- }
- else if (str_match(opt,"ex"))
- {
- /* add to exclude list */
- while((count < argc) && (argv[count][0] != '-'))
- {
- cur_excl->next = (struct elist *)malloc(sizeof(struct elist));
- Lnext(cur_excl);
- cur_excl->pattern = argv[count];
- cur_excl->next = NULL;
- count++;
- }
- }
- else if (str_match(opt,"reserve"))
- {
- for (c = argv[count] ; *(c+1) != '\0' ; c++) ;
- if (toupper(*c) == 'K')
- {
- *c == '\0';
- if (sscanf(argv[count],"%d", &num))
- {
- options.reserved = num * ONE_K;
- count++;
- }
- }
- else if (toupper(*c) == 'M')
- {
- *c == '\0';
- if (sscanf(argv[count],"%f", &ftmp))
- {
- options.reserved = (long) (ftmp * (float)(ONE_K * ONE_K));
- count++;
- }
- }
- else if (toupper(*c) == 'P')
- {
- *c == '\0';
- if (options.disk_size == 0) options.disk_size = IBM_DD;
- if (sscanf(argv[count],"%f",&ftmp))
- {
- options.reserved = (long)(ftmp * (float)(options.disk_size));
- count++;
- }
- }
- else if (sscanf(argv[count],"%d", &num))
- {
- options.reserved = num;
- count++;
- }
- }
- }
- }
- else
- {
- /* not an option.. must be path */
- /* add to path list */
- if (options.path_list == NULL)
- {
- options.path_list = (struct plist *)malloc(sizeof(struct plist));
- cur_path = options.path_list;
- }
- else
- {
- cur_path->next = (struct plist *)malloc(sizeof(struct plist));
- Lnext(cur_path);
- }
- cur_path->path = argv[count];
- cur_path->next = NULL;
- count++;
- }
- /* now put in defaults */
- if (options.disk_size == 0) options.disk_size = IBM_DD ;
- if (options.reserved == -1) options.reserved = options.disk_size / 100;
- if (options.reserved >= options.disk_size)
- {
- printf("Error: cannot reserve more space than disk size!\n");
- exit(1);
- }
- if (show_usage)
- {
- /* print the usage */
- printf("Usage: dcalc [ path ... ] [ option ... ]\n");
- printf(" path = path to scan for files\n");
- printf(" option is one of the following:\n");
- printf(" -hd = fit onto IBM 1.44MB high density disks\n");
- printf(" -dd = fit onto IBM 720K disks (default)\n");
- printf(" -s NNN = fit onto disk of size NNN\n");
- printf(" -reserve NNN = reserve NNN of the disk for filesystem, etc.\n");
- printf(" (default is 1%% to be safer)\n");
- printf(" -o file = send output to file\n");
- printf(" -ls path ... = add more paths\n");
- printf(" -in \"pat\" = include files matching pattern (* ? wild)\n");
- printf(" -ex \"pat\" = exclude files matching pattern\n");
- printf(" -rename = rename files for easy copying (A_file1 B_file2 ...) \n");
- printf(" -backup = use MSDOS backup mode, fit files across disks\n");
- printf(" NNN is I for I bytes ( 400 == 400 bytes)\n");
- printf(" Ik for I kilobytes ( 1k == 1024 bytes)\n");
- printf(" Fm for F megabytes ( 1.4m == 1048576 bytes)\n");
- printf(" Fp for F %% of disk space (cannot be used with -s)\n");
- printf(" I is any integer (whole number), F any float (real number)\n");
- }
- }
-
- int pattern_match(char *str, char *pat);
- struct flist *read_file_data_from_directory(char *path,
- struct flist *file_next);
-
- struct flist *get_files(void)
- {
- /* load in files from directories specified in path_list */
- struct plist *path_ptr=NULL;
- struct flist *file_list_top;
-
- if (options.path_list != NULL)
- {
- for (path_ptr = options.path_list; path_ptr != NULL; Lnext(path_ptr))
- {
- file_list_top = read_file_data_from_directory(path_ptr->path,
- file_list_top);
- }
- }
- else
- {
- /* default, scan current directory only */
- file_list_top = read_file_data_from_directory("",file_list_top);
- }
-
- return(file_list_top);
- }
-
- struct flist *read_file_data_from_directory(char *path,
- struct flist *file_top)
- {
- /* read in and append file data to list */
- char temp[200],line[100];
- char *path_name, *c;
- FILE *fptr;
- char perm[10], dum[20], name[50];
- struct ilist *inc_ptr;
- struct elist *exc_ptr;
- struct flist *file;
- long size = 0;
- int num,match;
-
- path_name = (char *) malloc (strlen(path)+1);
- strcpy(path_name, path);
- sprintf(temp,"%s %s > dcalc.tmp", SYS_LIST, path);
- system(temp);
- fptr = fopen("dcalc.tmp","r");
- if (fptr == NULL)
- {
- printf("Error opening dcalc.tmp\n");
- exit(1);
- }
- /* you might have to change this next bit if the format of your
- directory listing differs from the standard "ls -l" command */
- while(fgets(line,100,fptr))
- {
- num = sscanf(line,"%s%s%s%s%d%s%s%s%s",perm,dum,dum,dum,&size,
- dum,dum,dum,name);
- if (num == 9) /* removes "total nn" + other stuff */
- if (perm[0] == '-') /* files only, not directory etc.. */
- {
- /* if ls -F has been used, file name may end in special chars
- '/' directory and '@' link are screened out above, but '*'
- must be removed from the file name, or errors will occur */
- for (c = name; *c != '\0'; c++) if (*c == '*') *c == '\0';
- /* apply filters.. ? means match any 1 char
- * means match any chars up to . */
- if (options.include_list)
- {
- /* include filter */
- match = FALSE;
- for (inc_ptr = options.inc_list;
- inc_ptr != NULL; Lnext(inc_ptr))
- if (pattern_match(name,inc_ptr->pattern))
- {
- match = TRUE;
- break;
- }
- if (match == FALSE) size = -1;
- }
- if ((options.exclude_list) && (size >= 0))
- {
- /* exclude filter */
- for (exc_ptr = options.exc_list;
- exc_ptr != NULL; Lnext(exc_ptr))
- if (pattern_match(name,exc_ptr->pattern) == TRUE)
- {
- size = -1;
- break;
- }
- }
- if (size >= 0) /* filters set size = -1 if reject */
- {
- if (file_top == NULL)
- {
- file_top = (struct flist *)malloc(sizeof(struct flist));
- file = file_top;
- }
- else
- {
- file->next = (struct flist *)malloc(sizeof(struct flist));
- Lnext(file);
- }
- file->name = (char *)malloc(strlen(name)+2);
- strcpy(file->name,name);
- file->size = size;
- file->path = path_name;
- file->next = NULL;
- }
- }
- }
- sprintf(name, "%s dcalc.tmp", SYS_DELETE);
- system(name); /* remove the temporary file */
- return(file_top);
- }
-
- struct disklist *fit_files(struct flist *file_list_top)
- {
- /* fit files onto as few disks as possible */
- struct flist *file, *biggest, *first_file = NULL, *top, *disk_file;
- struct disklist *disk, *first_disk = NULL, *tdisk;
- int num_to_place = 0;
- long space = 0, num_disks = 0;
- long disk_space = 0;
- struct flist *null_file;
-
- null_file = (struct flist *) malloc (sizeof(struct flist));
- null_file->next = NULL;
- null_file->name = NULL;
- null_file->size = 0;
- null_file->path = NULL;
-
- top = file_list_top;
- disk_space = options.disk_size - options.reserved;
-
- if (options.backup)
- {
- /* split files across discs */
- space = 0;
- for(file = top; file != NULL; Lnext(file) )
- space += file->size;
- num_disks = (space / disk_space) + 1;
- space -= (num_disks - 1) * disk_space;
- first_disk = (struct disklist *)malloc(sizeof(struct disklist));
- disk = first_disk;
- disk->free_space = options.disk_size - space;
- disk->used_space = space;
- disk->perc_used = (float)100 * (float)disk->used_space / (float)options.disk_size;
- disk->next = NULL;
- disk->files = top;
- disk->number = (int)num_disks;
- }
- else
- {
- /* check that a file is not bigger than disk space */
- for(file = top; file != NULL; Lnext(file), num_to_place++ )
- if (file->size > disk_space)
- {
- printf("File \"%s\" will not fit onto a single disk!\n", file->name);
- printf("Use -backup mode to split across disks\n");
- exit(1);
- }
- while(num_to_place-- > 0)
- {
- /* find biggest file that will fit in remaining space */
- biggest = null_file;
- while (biggest == null_file)
- {
- for (file = top; file != NULL; Lnext(file) )
- if ((file->size <= space) && (file->size > biggest->size))
- biggest = file;
- if (biggest == null_file)
- {
- /* no more files will fit onto current disk, start a new one */
- if (first_disk == NULL)
- {
- first_disk = (struct disklist *)malloc(sizeof(struct disklist));
- disk = first_disk;
- }
- else
- {
- disk->used_space = disk_space - space;
- disk->free_space = options.disk_size - disk->used_space;
- disk->perc_used = (float)100.0 * (float)disk->used_space / (float)options.disk_size;
- disk->files = first_file;
- disk->next = (struct disklist *)malloc(sizeof(struct disklist));
- Lnext(disk);
- disk->number = (int)++num_disks;
- disk->next = NULL;
- }
- first_file = NULL;
- space = disk_space;
- }
- }
- /* have found biggest file that fits on disk... move it onto disk */
- if (first_file == NULL)
- {
- first_file = biggest;
- disk_file = biggest;
- }
- else
- {
- disk_file->next = biggest;
- Lnext(disk_file);
- }
- /* unlink from list */
- if (biggest == top)
- top = biggest->next;
- else {
- for (file = top; file->next != biggest; Lnext(file)) ;
- file->next = biggest->next;
- }
- space -= disk_file->size;
- disk_file->next = NULL;
- }
- if (space < options.disk_size)
- {
- disk->used_space = disk_space - space;
- disk->free_space = options.disk_size - disk->free_space;
- disk->perc_used = (float)100.0 * (float)disk->used_space / (float)options.disk_size;
- disk->files = first_file;
- disk->number = (int)num_disks++;
- disk->next = NULL;
- }
- else
- {
- for (tdisk = first_disk; tdisk->next != disk; Lnext(tdisk) ) ;
- tdisk->next = NULL;
- free(disk);
- }
- }
- free(null_file);
- return(first_disk);
- }
-
- void show_results(struct disklist *disk_list_top)
- {
- /* show results.. */
- struct disklist *disk;
- struct flist *file;
- char disk_letter;
- char temp[100], temp2[100];
-
- printf(" Disk size is %d bytes, %d bytes reserved for system\n",
- options.disk_size, options.reserved);
- if (options.backup)
- {
- disk = disk_list_top;
- printf("The backup takes up %d disk%c\n",disk->number,
- (disk->number > 1 ? 's' : ' ') );
- printf("The last disk is %.2f%% full ( %d used, %d free )\n",
- disk->perc_used, disk->used_space, disk->free_space);
- printf("Listing of files in backup:\n");
- for(file = disk->files; file != NULL; Lnext(file) )
- printf(" %s\n", file->name);
- }
- else if (options.rename_files)
- {
- printf("Files as split onto disks:\n");
- for (disk = disk_list_top; disk != NULL; Lnext(disk) )
- {
- disk_letter = (char)('A' + disk->number);
- printf("++ Disk %c ++ %d used, %d free, disk %.2f%% full ++\n",
- disk_letter, disk->used_space, disk->free_space,
- disk->perc_used);
- for(file = disk->files; file != NULL; Lnext(file) )
- {
- if (file->name[1] == '_')
- if (file->name[0] == disk_letter)
- sprintf(temp,"%s",file->name);
- else
- sprintf(temp,"%c%s", disk_letter, (file->name + 1));
- else
- sprintf(temp,"%c_%s", disk_letter, file->name);
- printf(" %s >>> \t%s\n", file->name, temp);
- }
- }
- printf("Rename files? (y/n) : ");
- scanf("%s",temp);
- if (temp[0] == 'y')
- {
- for (disk = disk_list_top; disk != NULL; Lnext(disk) )
- {
- disk_letter = (char)('A' + disk->number);
- for(file = disk->files; file != NULL; Lnext(file) )
- {
- if (file->name[1] == '_')
- if (file->name[0] == disk_letter)
- sprintf(temp2,"%s",file->name);
- else
- sprintf(temp2,"%c%s",disk_letter, (file->name + 1));
- else
- sprintf(temp2,"%c_%s", disk_letter, file->name);
- if (file->path[0] != '\0')
- sprintf(temp,"%s %s/%s %s/%s", SYS_RENAME,
- file->path, file->name,
- file->path, temp2);
- else
- sprintf(temp,"%s %s %s", SYS_RENAME, file->name, temp2);
- if ((file->name[0] == temp2[0]) && (file->name[1] == temp2[1]))
- /* no change */ ;
- else
- system(temp);
- /*printf("%s\n",temp);*/
- }
- }
- }
- }
- else
- {
- printf("Files as split onto disks:\n");
- for (disk = disk_list_top; disk != NULL; Lnext(disk) )
- {
- printf("++ Disk %c ++ %d used, %d free, disk %.2f%% full ++\n",
- (char)('A' + disk->number), disk->used_space, disk->free_space,
- disk->perc_used);
- for(file = disk->files; file != NULL; Lnext(file) )
- {
- printf(" %s\n", file->name);
- }
- }
- }
- }
-
- int str_match(char *src, char *match)
- {
- if (strlen(src) != strlen(match)) return(FALSE);
- while (*src != '\0')
- {
- if (*src != *match) return(FALSE);
- src++;
- match++;
- }
- return(TRUE);
- }
-
- int pattern_match(char *str, char *pat)
- {
- /* return TRUE if str matches pat */
- for (;(*pat != '\0') && (*str != '\0'); pat++, str++)
- {
- if (*pat == '?') ; /* dont try and match this one */
- else if (*pat == '*') /* search for char - after this one */
- {
- pat++;
- if (*pat == '\0') return(TRUE); /* '*' at end means don't match rest */
- /* search for *pat */
- while (*str != *pat)
- {
- if (*str == '\0') return(FALSE); /* ended with some left to match */
- str++;
- }
- }
- else /* match normally */
- if (*pat != *str) return(FALSE);
- }
- if (*pat != *str) return(FALSE); /* must end together */
- return(TRUE);
- }
-